package wechat

import (
	"AnniversaryNoticeLite/pkg/cache"
	"AnniversaryNoticeLite/pkg/config"
	"AnniversaryNoticeLite/pkg/log"
	"AnniversaryNoticeLite/pkg/requests"
	"encoding/json"
	"errors"
	"fmt"
	"go.uber.org/zap"
	"time"
)

func FlushAccessToken() (string, error) {
	url := fmt.Sprintf(
		"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
		config.Configs.App.AppID,
		config.Configs.App.AppSecret,
	)
	client := requests.NewRequestClient(10 * time.Second)
	resp, err := client.Get(url, nil)
	if err != nil {
		log.Logger.Error("请求刷新access_token失败", zap.Error(err))
		return "", errors.New("请求刷新access_token失败")
	}
	var data FlushAccessTokenRequest
	if err := json.Unmarshal([]byte(resp), &data); err != nil {
		log.Logger.Error("解析刷新access_token响应失败", zap.Error(err))
		return "", errors.New("解析刷新access_token响应失败")
	}
	if data.AccessToken == "" {
		log.Logger.Error("请求access_token失败", zap.Any("data", data))
		return "", errors.New(fmt.Sprintf("请求access_token失败 ErrCode:%d  ErrMsg:%s", data.Errcode, data.Errmsg))
	}
	log.Logger.Info("刷新access_token成功", zap.String("access_token", data.AccessToken))
	return data.AccessToken, nil
}

func GetAccessToken() (string, error) {
	lockKey, err := cache.LockManager.GetLock(log.Logger, cache.FlushAccessToken, "")
	if err != nil {
		return "", err
	}
	defer cache.LockManager.ReleaseLock(log.Logger, lockKey)

	if accessToken, ok := cache.CacheClient.Get("access_token"); ok && accessToken != "" {
		return accessToken.(string), nil
	}

	if accessToken, err := FlushAccessToken(); err != nil {
		return "", err
	} else {
		cache.CacheClient.Set("access_token", accessToken, time.Duration(60*90)*time.Second)
		return accessToken, nil
	}
}

func GetAllTemplate() ([]*TemplateItem, error) {
	accessToken, err := GetAccessToken()
	if err != nil {
		return nil, err
	}

	url := fmt.Sprintf(
		"https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=%s",
		accessToken,
	)
	client := requests.NewRequestClient(10 * time.Second)
	resp, err := client.Get(url, nil)
	if err != nil {
		log.Logger.Error("请求获取模版信息失败", zap.Error(err))
		return nil, errors.New("请求获取模版信息失败")
	}
	var data TemplateListResponse
	if err := json.Unmarshal([]byte(resp), &data); err != nil {
		log.Logger.Error("解析获取模版信息响应失败", zap.Error(err))
		return nil, errors.New("解析获取模版信息响应失败")
	}
	if data.Errcode != 0 {
		errMsg := fmt.Sprintf("获取模版信息失败")
		log.Logger.Error(errMsg, zap.Int("errcode", data.Errcode), zap.String("errmsg", data.Errmsg))
		return nil, errors.New(errMsg)
	}
	if data.TemplateList == nil {
		data.TemplateList = make([]*TemplateItem, 0, 0)
	}
	return data.TemplateList, nil
}

func SendTemplateMessage(touser, templateId string, data map[string]TemplateMessageDataItem) error {
	accessToken, err := GetAccessToken()
	if err != nil {
		return err
	}

	bodyData := &SendTemplateMessageRequest{
		Touser:     touser,
		TemplateId: templateId,
		Data:       data,
	}

	url := fmt.Sprintf(
		"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s",
		accessToken,
	)
	client := requests.NewRequestClient(10 * time.Second)
	postJsonOptions := &requests.RequestOptions{Body: bodyData}
	resp, err := client.Post(url, postJsonOptions)
	if err != nil {
		log.Logger.Error("请求发送模版消息失败", zap.Error(err))
		return errors.New("请求发送模版消息失败")
	}
	var responseData SendTemplateMessageResponse
	if err := json.Unmarshal([]byte(resp), &responseData); err != nil {
		log.Logger.Error("解析发送模版消息响应失败", zap.Error(err))
		return errors.New("解析发送模版消息响应失败")
	}
	if responseData.Errcode != 0 {
		log.Logger.Error("发送模版消息失败", zap.Int("errcode", responseData.Errcode), zap.String("errmsg", responseData.Errmsg))
		return errors.New("发送模版消息失败")
	}
	log.Logger.Info("发送模版消息成功", zap.String("touser", touser), zap.Any("data", data))
	return nil
}

func GetUserList(nextOpenid string) (*UserListResponse, error) {
	accessToken, err := GetAccessToken()
	if err != nil {
		return nil, err
	}

	url := fmt.Sprintf(
		"https://api.weixin.qq.com/cgi-bin/user/get?access_token=%s&next_openid=%s",
		accessToken,
		"",
	)

	client := requests.NewRequestClient(10 * time.Second)
	resp, err := client.Get(url, nil)
	if err != nil {
		log.Logger.Error("请求获取订阅用户信息失败", zap.Error(err))
		return nil, errors.New("请求获取订阅用户信息失败")
	}

	var data UserListResponse
	if err := json.Unmarshal([]byte(resp), &data); err != nil {
		log.Logger.Error("解析获取订阅用户信息响应失败", zap.Error(err))
		return nil, errors.New("解析获取订阅用户信息响应失败")
	}

	if data.Data.Openid == nil {
		data.Data.Openid = make([]string, 0, 0)
	}
	log.Logger.Info("获取订阅用户信息成功", zap.Any("data", data))
	return &data, nil
}
